﻿using FastApi.Attributes;

namespace FastApi
{
    public class FastService : IFastService
    {
        private readonly int serviceType;
        private readonly WebApplication app;

        private IServiceProvider _provider;
        internal IServiceProvider Provider
        {
            get
            {
                if (_provider == null)
                {
                    if (serviceType == 0)
                    {
                        _provider = app.Services;
                    }
                    else if (serviceType == 1)
                    {
                        Scope = app.Services.CreateScope();
                        _provider = Scope.ServiceProvider;
                    }
                    else
                    {
                        AsyncScope = app.Services.CreateAsyncScope();
                        _provider = AsyncScope.ServiceProvider;
                    }
                }

                return _provider;
            }
        }

        internal IServiceScope Scope { get; private set; }

        internal AsyncServiceScope AsyncScope { get; private set; }

        public FastService(WebApplication app, int serviceType)
        {
            this.app = app;
            this.serviceType = serviceType;
        }

#if NET8_0_OR_GREATER

        public T? GetKeyedService<T>(object? serviceKey)
        {
            return Provider.GetKeyedService<T>(serviceKey);
        }

        public IEnumerable<object?> GetKeyedServices(Type serviceType, object? serviceKey)
        {
            return Provider.GetKeyedServices(serviceType, serviceKey);
        }

        public IEnumerable<T> GetKeyedServices<T>(object? serviceKey)
        {
            return Provider.GetKeyedServices<T>(serviceKey);
        }

        public object GetRequiredKeyedService(Type serviceType, object? serviceKey)
        {
            return Provider.GetRequiredKeyedService(serviceType, serviceKey);
        }

        public T GetRequiredKeyedService<T>(object? serviceKey) where T : notnull
        {
            return Provider.GetRequiredKeyedService<T>(serviceKey);
        }

#endif

        public object GetRequiredService(Type serviceType)
        {
            return Provider.GetRequiredService(serviceType);
        }

        public T GetRequiredService<T>()
        {
            return Provider.GetRequiredService<T>();
        }

        public object? GetService(Type serviceType)
        {
            return Provider.GetService(serviceType);
        }

        public T? GetService<T>()
        {
            return Provider.GetService<T>();
        }

        public IEnumerable<object?> GetServices(Type serviceType)
        {
            return Provider.GetServices(serviceType);
        }

        public IEnumerable<T> GetServices<T>()
        {
            return Provider.GetServices<T>();
        }

        public void Dispose()
        {
            if (_provider != null)
            {
                try
                {
                    Scope.Dispose();
                }
                catch { }
            }
        }

        public async ValueTask DisposeAsync()
        {
            if (_provider != null)
            {
                try
                {
                    await AsyncScope.DisposeAsync();
                }
                catch { }
            }
        }
    }
}
